package com.solome.core;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import com.solome.base.Logger;

public class Dictionary<T> {
	// 错误反馈
	static final String ADD_ENTRY_KEYEXIST = "加入条目失败:目标KEY值已存在!";
	static final String ADD_ENTRY_LINKEXIST = "加入条目失败:目标助记词已存在!";
	static final String REMOVE_ENTRY_KEYNOTEXIST = "移除条目失败:目标KEY值不存在!";

	private AtomicInteger entries = new AtomicInteger(0);
	protected ConcurrentHashMap<Long, T> entryMap = new ConcurrentHashMap<Long, T>();
	protected ConcurrentHashMap<String, Long> linkMap = new ConcurrentHashMap<String, Long>();
	private boolean checkName = false;// 是否检查字符串

	/**
	 * 添加一个条目
	 * 
	 * @param key
	 *            索引KEY值
	 * @param mnemonic
	 *            助词字符串
	 * @param entry
	 *            目标对象
	 * @return 操作结果
	 */
	public boolean addEntry(int key, String mnemonic, T entry) {
		return addEntry((long) key, mnemonic, entry);
	}

	/**
	 * 添加一个条目
	 * 
	 * @param key
	 *            索引KEY值
	 * @param mnemonic
	 *            助记字符串
	 * @param entry
	 *            目标对象
	 * @return 操作结果
	 */
	public boolean addEntry(long key, String mnemonic, T entry) {
		Long _key = key;
		if (entryMap.containsKey(_key)) {
			Logger.error(this, ADD_ENTRY_KEYEXIST + " key=" + key
					+ ",mnemonic=" + mnemonic + ",T=" + entry + ",class="
					+ (entry != null ? entry.getClass() : null));
			return false;
		}
		if (checkName && linkMap.containsKey(mnemonic)) {
			Logger.error(this,
					ADD_ENTRY_LINKEXIST + ", key=" + key + ", mnemonic="
							+ mnemonic + ", exist=" + linkMap.get(mnemonic)
							+ ",class="
							+ (entry != null ? entry.getClass() : null));
			return false;
		}
		entryMap.putIfAbsent(_key, entry);
		if (checkName) {
			linkMap.putIfAbsent(mnemonic, _key);
		}
		entries.incrementAndGet();
		return true;
	}

	/**
	 * 计算词典内共有多少个对象
	 * 
	 * @return 对象个数
	 */
	public int countEntries() {
		return entries.intValue();
	}

	/**
	 * 获取字典的键值对集合
	 * 
	 * @return 键值对集合
	 */
	public Set<Map.Entry<Long, T>> entrySet() {
		return entryMap.entrySet();
	}

	/**
	 * 查询某个助记词的KEY
	 * 
	 * @param mnemonic
	 *            助记词
	 * @return 对应KEY
	 */
	public int getIntKey(String mnemonic) {
		return (int) getKey(mnemonic);
	}

	/**
	 * 获取某助记词的KEY
	 * 
	 * @param mnemonic
	 *            助记词
	 * @return 对应KEY
	 */
	public long getKey(String mnemonic) {
		if (hasMnemonic(mnemonic)) {
			return linkMap.get(mnemonic);
		}
		return -1;
	}

	/**
	 * 查询词典中是否包含某个KEY值
	 * 
	 * @param key
	 *            目标KEY
	 * @return 是/否
	 */
	public boolean hasIntKey(int key) {
		return hasKey(key);
	}

	/**
	 * 查询词典中是否包含某个KEY值
	 * 
	 * @param key
	 *            目标KEY
	 * @return 是否包含
	 */
	public boolean hasKey(long key) {
		Long _key = key;
		return entryMap.containsKey(_key);
	}

	/**
	 * 查询词典中是否包含某个助记词
	 * 
	 * @param mnemonic
	 *            助记词
	 * @return 是否包含
	 */
	public boolean hasMnemonic(String mnemonic) {
		return linkMap.containsKey(mnemonic);
	}

	/**
	 * @return the checkName
	 */
	public boolean isCheckName() {
		return checkName;
	}

	/**
	 * 获取词典的元素迭代器
	 *
	 * @return 元素迭代器
	 */
	public List<T> iterate() {
		ArrayList<T> tmp = new ArrayList<T>();
		tmp.addAll(entryMap.values());
		return tmp;
	}

	/**
	 * 获取词典的元素迭代器
	 * 
	 * @return 元素迭代器
	 */
	public List<T> iterateSet() {
		ArrayList<T> tmp = new ArrayList<T>();
		tmp.addAll(entryMap.values());
		return tmp;
	}

	/**
	 * 获取字典的索引集合
	 * 
	 * @return 索引集合
	 */
	public Set<Long> keySet() {
		return entryMap.keySet();
	}

	// /**
	// * 获取词典的元素列表
	// *
	// * @return 元素列表
	// */
	// public List<T> asArray() {
	// List<T> list = new ArrayList<T>();
	// list.addAll(entryMap.values());
	// return list;
	// }
	//
	/**
	 * 通过KEY值查找某个条目
	 * 
	 * @param key
	 *            目标KEY值
	 * @return 对应条目
	 */
	public T lookupEntry(int key) {
		return lookupEntry((long) key);
	}

	/**
	 * 通过KEY值查找某个条目
	 * 
	 * @param key
	 *            目标KEY值
	 * @return 对应条目
	 */
	public T lookupEntry(long key) {
		Long _key = key;
		return entryMap.get(_key);
	}

	/**
	 * 通过助记词查询某个条目
	 * 
	 * @param mnemonic
	 *            目标助记词
	 * @return 对应条目
	 */
	public T lookupEntry(String mnemonic) {
		if (hasMnemonic(mnemonic)) {
			Long key = linkMap.get(mnemonic);
			return lookupEntry(key);
		}
		return null;
	}

	/**
	 * 获取字典的助记词集合
	 * 
	 * @return 助记词集合
	 */
	public Set<String> mnemonicSet() {
		return linkMap.keySet();
	}

	/**
	 * 移除一个条目
	 * 
	 * @param key
	 *            目标KEY值
	 * @return 操作结果
	 */
	public boolean removeEntry(int key) {
		return removeEntry((long) key);
	}

	/**
	 * 移除一个条目
	 * 
	 * @param key
	 *            目标KEY值
	 * @return 操作结果
	 */
	public boolean removeEntry(long key) {
		Long _key = key;
		if (!entryMap.containsKey(_key)) {
			System.err.println(REMOVE_ENTRY_KEYNOTEXIST);
			return false;
		}
		if (entryMap.remove(_key) != null) {
			if (linkMap.containsValue(_key)) {
				for (Map.Entry<String, Long> entry : linkMap.entrySet()) {
					String linkKey = entry.getKey();
					Long keyRef = entry.getValue();
					if (keyRef.longValue() == _key.longValue()) {
						linkMap.remove(linkKey);
						entries.decrementAndGet();
						return true;
					}
				}
			}
		}
		return false;
	}

	/**
	 * 重置词典，此操作将导致词典内所有数据引用被清空
	 */
	public void reset() {
		entries.set(0);
		entryMap.clear();
		linkMap.clear();
	}

	/**
	 * @param checkName
	 *            the checkName to set
	 */
	public void setCheckName(boolean checkName) {
		this.checkName = checkName;
	}

	/**
	 * 更新某个值
	 * 
	 * @param index
	 *            索引键
	 * @param value
	 *            要更新的对象
	 */
	public void update(long index, T value) {
		if (hasKey(index)) {
			entryMap.replace(index, value);
		}
	}

	/**
	 * 更新某个值
	 * 
	 * @param mnemonic
	 *            助记词
	 * @param value
	 *            要更新的对象
	 */
	public void update(String mnemonic, T value) {
		if (linkMap.containsKey(mnemonic)) {
			Long key = linkMap.get(mnemonic);
			update(key, value);
		}
	}
}
